import { LingxinApiClientBase } from './LingxinApiClientBase.js'

/**
 * 语音输入语音输出（APP）
 */
export class LingxinApiClientV2v extends LingxinApiClientBase {
  // 灵芯应用的唯一标识
  lingxinAppCode = 'app_t_0f319bbe-c217-44c3-9ebf-f0ec1ac05ad2'
  // 任务ID
  taskId = ''

  // Promise 回调函数
  resolveCallback
  rejectCallback

  // 语音数据
  audioData = null

  constructor(lingxinAppId, appId, appLicenseKey) {
    super(lingxinAppId, appId, appLicenseKey)
    this.taskId = `${this.appId}^1^1`
  }

  /**
   * 语音转语音
   * @param {ArrayBuffer} audioData
   */
  voiceToVoice(audioData) {
    return new Promise((resolve, reject) => {
      if (!audioData) {
        reject('语音数据不能为空')
      }
      this.audioData = audioData
      if (!this.isConnected) {
        // 需要先初始化
        this.setupSocket()
          .then(result => {
            console.log('socket链接成功')
            this.doMessageInteraction(resolve, reject)
          })
          .catch(error => {
            console.log('socket链接错误：', error)
            reject(error)
          })
      } else {
        this.doMessageInteraction(resolve, reject)
      }
    })
  }

  doMessageInteraction(resolve, reject) {
    this.resolveCallback = resolve
    this.rejectCallback = reject

    // 发送start_task指令
    this.send(
      JSON.stringify({
        header: {
          action: 'start_task',
          task_id: this.taskId
        },
        payload: {
          input_mode: 'voice',
          output_mode: "no_voice",
          ai_app_code: this.lingxinAppCode,
          agent_code: this.lingxinAppCode,
          agent_basic_inputs: {},
          agent_ext_inputs: {
            play_prologue: false,
            show_asr_output: false
          }
        }
      })
    )
      .then(result => {
        console.log('发送start_task命令成功')
      })
      .catch(error => {
        console.log('发送start_task命令失败')
        this.rejectCallback(error)
      })
  }

  sendArrayBufferChunked(arrayBuffer, chunkSize = 30 * 1024) {
    return new Promise(async (resolve, reject) => {
        if (!arrayBuffer) {
            reject("音频数据为空")
            return
        }
        // 分片发送
        const totalSize = arrayBuffer.byteLength;
        const chunkCount = Math.ceil(totalSize / chunkSize);
        console.log(`开始分片发送，总大小: ${totalSize} bytes, 分片数: ${chunkCount}`)
        try {
            for (let i = 0; i < chunkCount;i++) {
              const start = i * chunkSize;
              const end = Math.min(start + chunkSize, totalSize);
              const chunk = arrayBuffer.slice(start, end)
              // console.log(`开始发送分片 ${i + 1}`)
              await this.send(chunk)
              console.log(`已发送分片 ${i + 1}/${chunkCount}, 大小: ${chunk.byteLength} bytes`)
            }
            resolve(true)
        } catch(error) {
            console.error('分片发送失败:', error);
            reject(error)
        }
    })
  }
  /**
   * 接收到云端的推送信息
   * @param {String | ArrayBuffer} message
   */
   onMessageRecived(message) {
    if (typeof message === 'string') {
      // 命令
      console.log('接收命令消息：', message)
      let data
      try {
        data = JSON.parse(message)
      } catch (error) {
        console.error('解析JSON消息失败:', error)
        this.rejectCallback('解析JSON消息失败')
        return
      }

      switch (data.header?.action) {
        case 'task_started':
          console.log('云端已初始化完成，开始发送二进制音频数据')
          // TODO: 如果语音数据过大，这里可能需要考虑分片发送
          this.sendArrayBufferChunked(this.audioData)
            .then(result => {
              console.log('发送语音数据成功')
              // 通知云端语音数据发送完成
              this.send(
                JSON.stringify({
                      header: {
                        action: 'end_audio',
                        task_id: this.taskId
                      },
                      payload: {}
                  })
                )
                .then(result => {
                  console.log('发送end_audio命令成功')
                })
                .catch(error => {
                  console.log('发送end_audio命令失败')
                  this.rejectCallback(error)
                })
            })
            .catch(error => {
              console.log('发送语音数据命令失败')
              this.rejectCallback(error)
            })
          break
        case 'task_terminated':
          console.log('任务已经中断')
          break
        case 'text_output':
          console.log('返回的文本结果：', message)
          // 这里只需要文本结果，不需要语音数据了
          let resultText = data.payload.result
          try {
              this.resolveCallback(JSON.parse(resultText))
          } catch (e) {
              this.rejectCallback("语音识别错误：", resultText)
          }
          break
        case 'task_stage_end':
          console.log('完成语音识别任务,准备发送任务结束指令')
          this.send(
                JSON.stringify({
                  header: {
                    action: 'end_task',
                    task_id: this.taskId
                  },
                  payload: {}
                })
            )
            .then(result => {
              console.log('发送end_task命令成功')
            })
            .catch(error => {
              console.log('发送end_task命令失败: ', error)
              this.rejectCallback(error)
            })
          break
        case 'audio_response_start':
          console.log('准备接受语音数据')
          break
        case 'audio_response_end':
          console.log('完成接受语音数据,准备发送任务结束指令')
          this.send(
            JSON.stringify({
              header: {
                action: 'end_task',
                task_id: this.taskId
              },
              payload: {}
            })
          )
            .then(result => {
              console.log('发送end_task命令成功')
            })
            .catch(error => {
              console.log('发送end_task命令失败')
              this.rejectCallback(error)
            })
          break
        case 'task_ended':
          console.log('任务已经结束')
          this.resolveCallback(this.audioData)
          break
        default:
          break
      }
    } else if (message instanceof ArrayBuffer) {
      // 音频数据
      console.log('接收音频数据：', message)
    } else {
      // 未知类型
      console.log('接收到消息：', message)
    }
  }
}
